/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020.
 * Description: support rtos swxn
 * Author: hejiani
 * Create: 2020-10-21
 */
#include <asm/current.h>
#include <linux/mman.h>
#include <linux/unistd.h>
#include <linux/capability.h>
#include <linux/seq_file.h>
#include <linux/task_struct_extend.h>
#include <internal/rtos_swxn.h>
#include "internal.h"

static unsigned int swxn_status __ro_after_init = SWXN_DISABLE;
static unsigned int swxn_cap __ro_after_init = CAP_SYS_ADMIN;

static int __init swxn_setup(char *str)
{
	unsigned long mode;

	if (!kstrtoul(str, 0, &mode))
		if (mode <= SWXN_DISABLE)
			swxn_status = mode;
	return 1;
}
__setup("swxn=", swxn_setup);

static int __init swxn_cap_setup(char *str)
{
	unsigned long cap;

	if (!kstrtoul(str, 0, &cap))
		if (cap <= CAP_LAST_CAP)
			swxn_cap = cap;
	return 1;
}
__setup("swxn_cap=", swxn_cap_setup);

int check_swxn(struct task_struct *p, unsigned long prot, const char *func_name)
{
	struct rtos_task_struct *rtos_task = task_to_rtos_task(p);
	unsigned int pid_swxn;
	unsigned long flag = PROT_WRITE | PROT_EXEC;

	if (!rtos_task)
		return -ESRCH;

	pid_swxn = rtos_task->swxn;
	if (pid_swxn == SWXN_DISABLE)
		return 0;

	if ((prot & flag) == flag) {
		pr_warn("[SWXN] %s (pid %d, tid %d), "
			"%s: Both W and X exist!\n",
			current->comm, task_tgid_vnr(current),
			task_pid_vnr(current), func_name);
		if (pid_swxn == SWXN_ENFORCING)
			return -1;
	}
	return 0;
}

int init_pid_swxn(struct task_struct *p)
{
	struct rtos_task_struct *rtos_task = task_to_rtos_task(p);

	if (!rtos_task)
		return -ESRCH;
	rtos_task->swxn = swxn_status;
	return 0;
}

unsigned int get_swxn_status(void)
{
	return swxn_status;
}

unsigned int get_swxn_cap(void)
{
	return swxn_cap;
}
